/***********************************************************************
 * Fulguro Four threads for four watersheds
 ***********************************************************************/
#include <flgrCoreTypes.h>
#include <flgrCoreErrors.h>
#include <flgrCoreData.h>
#include <flgrCoreIO.h>
#include <flgrCoreCompare.h>
#include <flgrCoreReplace.h>
#include <flgrCoreThreads.h>
#include <flgrImageIO.h>
#include <flgrMeasureBase.h>
#include <flgrMorphoBase.h>
#include <flgrMorphoWatershed.h>
#include <flgrMorphoGeodesy.h>
#include <flgrMorphoLabel.h>
#include <flgrMorphoDistance.h>
#include <time.h>


/*! 
 * \example multithread_watershed.c <B>Four threads for four watersheds</B>
 */




#define BENCH_FUCTION(nbtime,textinfo,function,...)			\
  {									\
    time_t before_t, after_t;						\
    clock_t before_c, after_c;						\
    int i;								\
									\
    before_t = time(NULL);						\
    before_c = clock();							\
									\
    for(i=0;i<nbtime;i++) {						\
      function(__VA_ARGS__);						\
    }									\
    									\
    after_t = time(NULL);						\
    after_c = clock();							\
									\
    printf(textinfo " System time : %d us, CPU time : %d us \n",	\
	   (int) (((after_t-before_t)*1000000)/nbtime),			\
	   (int) ((after_c-before_c)/(CLOCKS_PER_SEC/1000000)/nbtime)); \
  }







int thread_watershed(void *param) {
  FLGR_ThreadsArg *arg = (FLGR_ThreadsArg *) param;
  FLGR_Data2D *label = (FLGR_Data2D *) arg->argv[0];
  FLGR_Data2D *src = (FLGR_Data2D *) arg->argv[1];
  FLGR_Type *type = (FLGR_Type*) arg->argv[2];


  flgr2d_watershed(label, src, *type);


  return 0;
}




void flgr2d_threaded_4_watershed(FLGR_Data2D *imLabel1, FLGR_Data2D *imin1, FLGR_Connexity *type1,
				 FLGR_Data2D *imLabel2, FLGR_Data2D *imin2, FLGR_Connexity *type2,
				 FLGR_Data2D *imLabel3, FLGR_Data2D *imin3, FLGR_Connexity *type3,
				 FLGR_Data2D *imLabel4, FLGR_Data2D *imin4, FLGR_Connexity *type4) {

  FLGR_ThreadsArgList *arglist = flgr_threads_create_argument_list(4);
  
  flgr_threads_set_argument(arglist, 0, 3, imLabel1, imin1, type1);
  flgr_threads_set_argument(arglist, 1, 3, imLabel2, imin2, type2);
  flgr_threads_set_argument(arglist, 2, 3, imLabel2, imin2, type2);
  flgr_threads_set_argument(arglist, 3, 3, imLabel2, imin2, type2);

  flgr_threads_start(arglist, 4, 1, thread_watershed);

  flgr_threads_destroy_argument_list(arglist);

}






int main(void) {
  FLGR_Data2D *imin,*imtmp,*imFilter,*imDistance,*imMarker,*imMaxima,*imWatershed;
  FLGR_Data2D *imLabel,*imLabel2,*imLabel3,*imLabel4;
  FLGR_Data2D *nhb1,*nhb2,*nhb3,*nhb4,*nhb5;
  
  FLGR_Vector *vec_min, *vec_max;
  FLGR_Vector *vec_hmin;

  imin         = flgr2d_load_pgm("../../images/gray/beans.pgm");
  imtmp        = flgr2d_create_from(imin);
  imFilter     = flgr2d_create_from(imin);
  imDistance   = flgr2d_create_from(imin);
  imMarker     = flgr2d_create_from(imin);
  imMaxima     = flgr2d_create_from(imin);

  imLabel      = flgr2d_create_from(imin);
  imLabel2     = flgr2d_create_from(imin);
  imLabel3     = flgr2d_create_from(imin);
  imLabel4     = flgr2d_create_from(imin);

  imWatershed  = flgr2d_create_from(imin);

  vec_min  = flgr_vector_create(imin->spp,imin->type);
  vec_max  = flgr_vector_create(imin->spp,imin->type);
  vec_hmin = flgr_vector_create(imin->spp,imin->type);
  flgr_vector_populate_from_string(vec_hmin,"1");


  nhb1 = flgr2d_create_neighborhood(3,3,imin->spp,imin->type,FLGR_RECT,FLGR_8_CONNEX);
  nhb2 = flgr2d_create_neighborhood(5,5,imin->spp,imin->type,FLGR_RECT,FLGR_8_CONNEX);
  nhb3 = flgr2d_create_neighborhood(7,7,imin->spp,imin->type,FLGR_RECT,FLGR_8_CONNEX);
  nhb4 = flgr2d_create_neighborhood(9,9,imin->spp,imin->type,FLGR_RECT,FLGR_8_CONNEX);
  nhb5 = flgr2d_create_neighborhood(11,11,imin->spp,imin->type,FLGR_RECT,FLGR_8_CONNEX);

  flgr2d_replace_I_with_S_S_I(imin,imin,"==","255","254",imin);

  //Filter
  BENCH_FUCTION(100000,"Open Filter",flgr2d_open,imtmp,imin,nhb1);
  flgr2d_close(imFilter,imtmp,nhb1);

  // Distance
  flgr2d_replace_I_with_S_S_S(imtmp,imFilter,"<","128","255","0");
  flgr2d_distance(imDistance,imtmp,nhb1->connexity);

  // Distance Maxima
  flgr2d_regional_hmaxima(imMaxima,imDistance,vec_hmin,nhb1->connexity);
  flgr2d_replace_I_with_S_S_S(imtmp,imMaxima,">","0","255","0");
  flgr2d_dilate(imMaxima,imtmp,nhb5);

  // Labelize Maxima
  flgr2d_label(imLabel, imMaxima, nhb1->connexity);
  flgr2d_label(imLabel2, imMaxima, nhb1->connexity);

  // Watershed
  BENCH_FUCTION(1000,"Watershed",flgr2d_watershed,imLabel, imin, nhb1->connexity);

  BENCH_FUCTION(1000,"4 Threads 4 Watersheds",
		flgr2d_threaded_4_watershed,
		imLabel, imin, &(nhb1->connexity),
		imLabel2, imin, &(nhb1->connexity),
		imLabel3, imin, &(nhb1->connexity),
		imLabel4, imin, &(nhb1->connexity));


  flgr2d_watershed_build_line(imWatershed, imLabel, nhb1->connexity);
  flgr2d_replace_I_with_S_S_I(imWatershed,imWatershed,"==","1","255",imin);

  flgr2d_save_pgm(imFilter,"filter.pgm",5);
  flgr2d_save_pgm(imDistance,"distance.pgm",5);
  flgr2d_save_pgm(imMaxima,"maxima.pgm",5);
  flgr2d_save_pgm(imLabel,"label.pgm",5);
  flgr2d_save_pgm(imWatershed,"watershed.pgm",5);

  flgr2d_destroy(imin);
  flgr2d_destroy(imtmp);
  flgr2d_destroy(imFilter);
  flgr2d_destroy(imDistance);
  flgr2d_destroy(imMarker);
  flgr2d_destroy(imMaxima);
  flgr2d_destroy(imLabel);
  flgr2d_destroy(imLabel2);
  flgr2d_destroy(imLabel3);
  flgr2d_destroy(imLabel4);
  flgr2d_destroy(imWatershed);
  flgr2d_destroy(nhb1);
  flgr2d_destroy(nhb2);
  flgr2d_destroy(nhb3);
  flgr2d_destroy(nhb4);
  flgr2d_destroy(nhb5);

  flgr_vector_destroy(vec_max);
  flgr_vector_destroy(vec_min);
  flgr_vector_destroy(vec_hmin);
 
  return 0;
}
